#include "NetworkManager.h"
#include "DatabaseManager.h"



// 线程工作函数
static void client_handler(void *arg)
{
     ClientRequest *req = static_cast<ClientRequest *>(arg); // 强制转换

     // // 处理请求
     string response = RequestHandler::getInstance().handleRequest(req->buffer);

     // 发送响应
     send(req->client_fd, response.c_str(), response.length(), 0);
     cout << "after parse:" << endl;
     cout << response << endl;
     epoll_event ev;
     ev.events = EPOLLIN | EPOLLET;
     ev.data.fd = req->client_fd;
     epoll_ctl(req->epoll_fd, EPOLL_CTL_MOD, req->client_fd, &ev);
     // 清理


     delete[] req->buffer;
     delete req;
}

void NetworkManager::SetupSocket() // 用来设置套接字
{
     // 用来设置套接字
     // 获取套接字  使用IPV4
     m_listenfd = Socket(AF_INET, SOCK_STREAM, 0);
     sockaddr_in server;
     // 填充套接字的结构体
     server.sin_family = AF_INET;
     server.sin_port = htons(m_port);
     server.sin_addr.s_addr = htonl(INADDR_ANY);
     Bind(m_listenfd, (sockaddr *)&server, sizeof(server));
     Listen(m_listenfd, BLOCK_SIZE);
     // 改变socket的状态使用F_SETFL中的O+NONBLOCK来改变为非阻塞状态
     fcntl(m_listenfd, F_SETFL, O_NONBLOCK);
}

// 通过构造函数来实现创建套接字并且填加进入epoll中
NetworkManager::NetworkManager(int port) : m_port(port), m_requestHandler(RequestHandler::getInstance())
{
     // 清空缓冲区
     memset(rbuff, 0, BUFFER_LENGTH);
     memset(wbuff, 0, BUFFER_LENGTH);
     // 创建一个套接字
     SetupSocket();
     // 创造一个epoll句柄
     m_epollfd = Epoll_create(1);
     epoll_event ev;
     ev.events = EPOLLIN;
     ev.data.fd = m_listenfd;
     Epoll_ctl(m_epollfd, EPOLL_CTL_ADD, m_listenfd, &ev);
     // 创建一个线程池最大为1000最小为100
     m_threadPool = create_thread_pool(1000, 100);
}

// 开启这个网络服务器
void NetworkManager::start()
{
     // 设置一个epoll中事件最大长度
     epoll_event events[EVENTS_LENGTH];
     epoll_event ev;
     printf("start epoll_wati  epollfd = %d\n", m_epollfd);
     while (true)
     {
          //-1表示一直循环等待
          int nready = Epoll_wait(m_epollfd, events, EVENTS_LENGTH, -1);
          for (int i = 0; i < nready; ++i)
          {
               int curfd = events[i].data.fd;
               // 如果这个需要处理的事件为网络服务的套接字
               if (curfd == m_listenfd)
               {
                    // 申明一个套接字的地址用来接受客户端的套接字
                    sockaddr_in clientAddr;
                    socklen_t len = sizeof(clientAddr);
                    int clientfd = accept(m_listenfd, (sockaddr *)&clientAddr, &len);
                    if (clientfd == -1)
                    {
                         perror("accept fail\n");
                         continue;
                    }
                    fcntl(clientfd, F_SETFL, O_NONBLOCK);
                    printf("client %s:%d\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
                    // 设置event以及将该事件的套接字传入event中注册
                    ev.events = EPOLLIN | EPOLLET; // 只读状态和水平触发
                    ev.data.fd = clientfd;
                    Epoll_ctl(m_epollfd, EPOLL_CTL_ADD, clientfd, &ev);
               }
               else if (events[i].events & EPOLLIN)
               {
                    // read
                    int ret = recv(curfd, rbuff, BUFFER_LENGTH, 0);
                    if (ret > 0)
                    {
                         // 创建客户端请求并且填充进去
                         ClientRequest *req = new ClientRequest;
                         req->client_fd = curfd;
                         req->buffer = new char[ret + 1];
                         memcpy(req->buffer, rbuff, ret);
                         req->buffer[ret] = '\0';
                         req->length = ret;
                         req->epoll_fd = m_epollfd;
                         ev.events = EPOLLET; // 只保留ET模式
                         ev.data.fd = curfd;

                         Epoll_ctl(m_epollfd, EPOLL_CTL_MOD, curfd, &ev);
                         //提交给线程池
                         requst_thread_work(m_threadPool,client_handler,req);      
                    }
                    else if (ret == 0)
                    {
                         printf("client %d disconnected\n", events[i].data.fd);
                         Epoll_ctl(m_epollfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
                         close(events[i].data.fd);
                    }
                    else if (ret == -1) // 没有数据可读了
                    {
                         printf("no data can read\n");
                         continue;
                    }
               }
               // else if (events[i].events & EPOLLOUT)
               // {
               //      // write
               //      send(curfd, wbuff, strlen(wbuff), 0);
               //      m_requestHandler.parseOperation(wbuff);
               //      memset(wbuff, 0, sizeof(wbuff));
               //      ev.events = EPOLLIN;
               //      ev.data.fd = curfd;
               //      Epoll_ctl(m_epollfd, EPOLL_CTL_MOD, curfd, &ev);
               // }
          }
     }
     close(m_listenfd);
      // 清理线程池
     destroy_thread_pool(m_threadPool);
}